/*****************************************************************************
 *
 *              Utility.c -- Firing Line Controller Utility Program
 *
 *****************************************************************************
 * FileName:        Utility.c
 *
 * Author:          Sheng Chen and Eric DeYoung
 *
 * Date:            Dec 08, 2008
 *
 * Description:     Firing Line Controller Utility Program. 
 *
 *****************************************************************************/


#include <avr/io.h>
#include <avr/interrupt.h>
#include <string.h>
#include <stdlib.h>
#include "timer.h"
#include "lcdcontrol.h"
#include "screen.h"
#include "SPI.h"
#include "menu.h"
#include "MRF24J40.h"

#define BuzzerSwitch 0

volatile uint8_t WaitTime = 0, NumOfPlates = 0;
volatile uint16_t voltage = 0, temperature = 0;

void BatteryChargerON(void);


void Buzzer_ON(void) //Enable Buzzer
{
	PORTA |= _BV(BuzzerSwitch);
}

void Buzzer_OFF(void) //Disable Buzzer
{
	PORTA &= ~_BV(BuzzerSwitch);
}	


void BatteryChargerOFF(void) //Disable Battery Charger
{
	PORTD &=~_BV(3);  //Battery Charger Control is on PORTD PIN 3
}


void PowerSavingMode_init(void) //Enable Power Saving Mode
{
    PCMSK0 |= (1<<PCINT4); //  tell pin change mask to listen to PORTA PIN4 Up Button
    PCMSK0 |= (1<<PCINT5); //  tell pin change mask to listen to PORTA PIN5 Down Button
    PCMSK0 |= (1<<PCINT6); //  tell pin change mask to listen to PORTA PIN6 Back Button
    PCMSK0 |= (1<<PCINT7); //  tell pin change mask to listen to PORTA PIN7 Enter Button

   	PCICR |= _BV(PCIE0);
}

void ADC_init(void) //Analog to Digital Converter Initialization
{
	DIDR0 = _BV(ADC2D) | _BV(ADC1D);

	ADCSRA = _BV(ADEN) | _BV(ADIF) | _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0) ;
	//Enable A2D converter; Clear ADIF bit; Set prescale 1:128;
}


void read_voltage(void)//Read Battery Voltage
{
	BatteryChargerOFF();
	
	ADMUX = _BV(REFS1) | _BV(REFS0)| _BV(ADLAR) | 2; //Switch ADC to Battery Voltage Channel

	ADCSRA |= _BV(ADSC); // Start the conversion

	while((ADCSRA & _BV(ADIF))==0); //Wait for conversion to complete

	voltage = (uint8_t) ADCH * 10;
	
	if(voltage < 1000)
		BatteryChargerOFF();

}

void read_temperature(void)//Read Temperature Sensor
{
	ADMUX = _BV(REFS1) | _BV(REFS0)| _BV(ADLAR) | 1; //Switch ADC to Temperature Channel

	ADCSRA |= _BV(ADSC); // Start the conversion

	while((ADCSRA & _BV(ADIF))==0); //Wait for conversion to complete

	temperature = (ADCH * 10 - 1012.5)/ (0.027791);

	if(temperature > 50000) //Turn OFF Battery Charger when battery
	{						//temperature is above 50 Degree Cel
		BatteryChargerOFF();
	}
}

void BatteryChargerON(void) //Enable Battery Charger
{
	PORTD |= _BV(3); //Battery Charger Control is on PORTD PIN 3

	read_temperature();
}


void Device_init(void) //Start Up Controller Initializaion
{
	BatteryChargerOFF(); //Battery Charger MUST be OFF during initialization

	timer_init(); //Initialize the counter timer

	LCD_init(); //Initialize the LCD screen

	PowerSavingMode_init(); //Enable Power Saving Mode

	ADC_init(); //Initialize ADC

	// SET MOSI, SCK, CSn, WAKE, RESETn AND TP1 TO OUTPUTS
	DDRB = (1<<MOSI)|(1<<SCK)|(1<<CSn)|(1<<WAKE)|(1<<RESETn)|(1<<TP1);

	DDRA |= _BV(BuzzerSwitch); //Enable Buzzer

	DDRD |= _BV(3); //Enable Battery Charger Control

	PORTA &= ~_BV(BuzzerSwitch); //Set Buzzer OFF

	SPI_MasterInit();
	
	RFInitialize();

	sei(); //Enable interrupt

	Welcome();

	LCD_CLS();

	read_voltage();
}

uint8_t Duplicated_ID_Check(void) //Duplicated Rack ID Check
{
	uint8_t i;

	for(i=0;i<NumOfRacks;i++)
	{
		if(Device_ID == atoi(PScore[i][0]))
		{
				return(0);
		}
	}
	return(1);
}


void FormatTimeData(void)  //Total Time Data Processing Function
{
	uint8_t  StrLength, i;
	
	uint16_t Time_score;

	itoa(Device_ID, PScore[NumOfRacks][0], 10);

	Time_score = (Score_MSB << 8) | (Score_LSB);

	ltoa(Time_score, PScore[NumOfRacks][1], 10);
	
	if(Device_ID < 10)
	{
		PScore[NumOfRacks][0][2] = PScore[NumOfRacks][0][0];
		PScore[NumOfRacks][0][1] = '0';
		PScore[NumOfRacks][0][0] = '0';
	}
	else if(Device_ID < 100)
	{
		PScore[NumOfRacks][0][2] = PScore[NumOfRacks][0][1];
		PScore[NumOfRacks][0][1] = PScore[NumOfRacks][0][0];
		PScore[NumOfRacks][0][0] = '0';
	}

	StrLength = strlen(PScore[NumOfRacks][1]);

	for(i=3;i>0;i--)
	{
		PScore[NumOfRacks][1][StrLength] = PScore[NumOfRacks][1][StrLength - 1];
		StrLength--;
	}
	
	StrLength = strlen(PScore[NumOfRacks][1]) ;

	PScore[NumOfRacks][1][StrLength - 4] = '.';

	StrLength = strlen(PScore[NumOfRacks][1]);

	if(StrLength == 5)
	{		
		for(i=6;i>0;i--)
		{
			PScore[NumOfRacks][1][i] = PScore[NumOfRacks][1][StrLength];
			StrLength--;
		}
		PScore[NumOfRacks][1][0] =' ';
	} 

	if(Time_score > 60000) //Time Out when Received Score is Greater Than 60000 ms
	{
		PScore[NumOfRacks][1][0] = 'T';
		PScore[NumOfRacks][1][1] = '/';
		PScore[NumOfRacks][1][2] = 'O';
		PScore[NumOfRacks][1][3] = ' ';
		PScore[NumOfRacks][1][4] = ' ';
		PScore[NumOfRacks][1][5] = ' ';
	}

	NumOfRacks++;
}

void FormatScoreData(void) //Shoot For Score Data Processing Function
{
	uint8_t  StrLength, i;
	uint16_t Time_score;

	itoa(Device_ID, PScore[NumOfRacks][0], 10);

	Time_score = (Score_MSB << 8) | (Score_LSB);

	itoa(Time_score, PScore[NumOfRacks][1], 10);
	
	if(Device_ID < 10)
	{
		PScore[NumOfRacks][0][2] = PScore[NumOfRacks][0][0];
		PScore[NumOfRacks][0][1] = '0';
		PScore[NumOfRacks][0][0] = '0';
	}
	else if(Device_ID < 100)
	{
		PScore[NumOfRacks][0][2] = PScore[NumOfRacks][0][1];
		PScore[NumOfRacks][0][1] = PScore[NumOfRacks][0][0];
		PScore[NumOfRacks][0][0] = '0';
	}

	StrLength = strlen(PScore[NumOfRacks][1]);

	if(StrLength == 1)
	{
		for(i=5;i>0;i--)
		{
			PScore[NumOfRacks][1][i] = PScore[NumOfRacks][1][i-1];
			PScore[NumOfRacks][1][i-1]=' ';
		}
	}

	NumOfRacks++;
		
}

void ClearData(void) //Clear Stored Data
{
	uint8_t i,j, k;

	for(i=0;i<NumOfRacks+1;i++)
	{
		for(j=0;j<3;j++) //Clear ID
			PScore[i][0][j] = ' ';
	
		for(k=0;k<7;k++) //Clear Score
			PScore[i][1][k]=' ';
	}
} 

void CollectingDetailScore(void) //Obtain Detail Score fromn Racks and Process Data into Correct Format
{
	uint8_t  StrLength, i;
	uint16_t DetailTime;

	DetailTime = (Score_MSB << 8) | (Score_LSB);

	ltoa(DetailTime, DetailScore[0][NumOfPlates], 10);

	StrLength = strlen(DetailScore[0][NumOfPlates]);

	for(i=3;i>0;i--)
	{
		DetailScore[0][NumOfPlates][StrLength] = DetailScore[0][NumOfPlates][StrLength - 1];
		StrLength--;
	}
	
	StrLength = strlen(DetailScore[0][NumOfPlates]);

	DetailScore[0][NumOfPlates][StrLength - 4] = '.';

	StrLength = strlen(DetailScore[0][NumOfPlates]);

	if(StrLength == 5)
	{		
		for(i=6;i>0;i--)
		{
			DetailScore[0][NumOfPlates][i] = DetailScore[0][NumOfPlates][StrLength];
			StrLength--;
		}
		DetailScore[0][NumOfPlates][0] =' ';
	} 
	NumOfPlates++;

}


ISR(PCINT0_vect) //Pushbutton Interrupt
{ 
		TimeOut = 0;
		PORTD |= _BV(4); //Turn on the LCD Backlight
}


